<template>
    <div class="canvas_note">
        <div class="head">
            <ul>
                <li v-for="item in colors" :key="item" :style="{background:item}" :class="{active:item === color}"
                    @click="changeColor(item)"></li>
            </ul>
            <div class="operate">
                <label>
                    <i class="el-icon-picture-outline" title="选择图片"></i> <input type="file" @change="onPicture" />
                </label>
                <i class="el-icon-s-tools" title="保存导出" @click="exportImg"></i>
                <img src="@/assets/icon-undo.png" alt="" @click="undo" title="撤销">
                <img src="@/assets/icon-redo.png" alt="" @click="redo" title="恢复">
                <img src="@/assets/icon-clear.png" alt="" @click="clearAll" title="清除">
            </div>
        </div>
        <div class="canvs">
            <canvas class="canvasbg" ref="canvasbg"></canvas>
            <canvas class="canvas" ref="canvas" @mousedown="mousedown" @mousemove="mousemove"></canvas>
        </div>
    </div>
</template>
<script>
    export default {
        name: "canvas_note",
        data() {
            return {
                colors: ["#222222", "#5cb85c", "#f0ad4e", "#d9534f", "#ffffff"],
                color: "#222222",
                isdown: false, // 鼠标点击下，开始画图
                path: [],    // 当前画的路径
                command: new this.$utils.Command(),   // 当前的所有任务，命令模式
            }
        },
        mounted() {
            this.$refs.canvas.width = this.$refs.canvas.offsetWidth;
            this.$refs.canvas.height = this.$refs.canvas.offsetHeight;
            this.$refs.canvasbg.width = this.$refs.canvasbg.offsetWidth;
            this.$refs.canvasbg.height = this.$refs.canvasbg.offsetHeight;
            let ctx = this.$refs.canvas.getContext("2d");
            let ctxBg = this.$refs.canvasbg.getContext("2d");

            this.ctx = ctx;
            this.ctxBg = ctxBg;
            ctx.lineWidth = 1;
            ctxBg.lineWidth = 1;
            window.addEventListener("mouseup", this.mouseup.bind(this));
            this.changeColor(this.color);
        },
        methods: {
            changeColor(e) {
                this.color = e;
                let c = this.$utils.colorToRGB(e, 0.06);
                this.ctx.strokeStyle = c;
            },
            mousedown(e) {
                if (!this.color) {
                    this.$message.warning({
                        message: "请先选择颜色",
                        duration: 1000
                    });
                    return;
                }
                this.ctx.beginPath();
                this.ctx.moveTo(e.offsetX, e.offsetY);
                this.path = [];
                this.path.push({
                    x: e.offsetX,
                    y: e.offsetY
                });
                this.isdown = true;
            },
            mousemove(e) {
                if (this.isdown) {
                    this.ctx.lineTo(e.offsetX, e.offsetY);

                    this.ctx.stroke();
                    this.path.push({
                        x: e.offsetX,
                        y: e.offsetY
                    });
                }
            },
            mouseup(e) {
                if (this.isdown && this.path.length > 0) {
                    let ctx = this.ctx;
                    let canvas = this.$refs.canvas;
                    this.isdown = false;
                    ctx.closePath();
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    // 加入任务队列
                    this.command.add(this.drawnOne.bind(this, this.path, this.color), true);
                    this.path = [];
                }
            },
            drawnOne(path, color) {
                if (path.length > 0) {
                    let ctx = this.ctxBg;
                    ctx.beginPath();
                    ctx.strokeStyle = color;
                    ctx.moveTo(path[0].x, path[0].y);
                    for (let i = 1; i < path.length; i++) {
                        ctx.lineTo(path[i].x, path[i].y);
                        ctx.stroke();
                    }
                    ctx.closePath();
                }
            },
            clearAll() {
                this.command.clear();
                this.clear();
            },
            clear() {
                let canvas = this.$refs.canvasbg;
                this.ctxBg.clearRect(0, 0, canvas.width, canvas.height);
            },
            undo() {
                this.command.undo(this.clear.bind(this));
            },
            redo() {
                this.command.redo(this.clear.bind(this));
            },
            drawImage(img, w, h) {
                this.ctxBg.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h);
            },
            async onPicture(e) {
                // 防止选择同样的图片，导致 change 事件不触发
                let target = e.target.cloneNode();
                let canvas = this.$refs.canvasbg;
                e.target.value = "";
                if (target.files.length > 0) {
                    this.clear();
                    let file = target.files[0];
                    let img = await this.$utils.fileToImg(file);
                    this.drwanImg(img);
                }
            },
            drwanImg(img){
                // 把图片画上去
                let canvas = this.$refs.canvasbg;
                let w, h;
                w = canvas.width;
                h = img.height * canvas.width / img.width;
                this.command.add(this.drawImage.bind(this, img, w, h), true);
            },
            async exportImg(){
                // 外面组件，通过 refs 调用这个方法 导出图片
                let base = this.$refs.canvasbg.toDataURL("image/png");
                let file = this.$utils.dataURLtoFile(base); // window.atob 将 base64 转换为 file
                let fd = new FormData(); // 创建form对象
                fd.append("file", file); // 通过append向form对象添加数据
                let res = await this.$api.uploadfile(fd);
                return Promise.resolve(res);
            },
            async initSetImg(url){
                // 外面组件，修改的时候，通过传入 url ，设置图片
                this.clearAll();
                if(!url){
                    // 如果不存在，则是清除
                    return ;
                }
                let img = await this.$utils.loadImg(url,{crossOrigin:"Anonymous"}); 
                this.drwanImg(img);
            }
        },
        destroyed(){
            window.removeEventListener("mouseup", this.mouseup.bind(this));
            this.command = null;
        }
    }
</script>
<style lang="scss" scoped>
    .canvas_note {
        width: 100%;
        height: 100%;
        background: #fff;

        .head {
            height: 28px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px dashed #ccc;

            ul {
                li {
                    float: left;
                    width: 16px;
                    height: 16px;
                    margin-left: 6px;
                    border: 2px solid #222;
                    border-radius: 50%;
                    transition: .2s ease-in-out;
                    cursor: pointer;

                    &.active,
                    &:hover {
                        box-shadow: 0 0 6px #222;
                    }
                }
            }

            div.operate {
                line-height: 26px;
                img {
                    margin-left: 10px;
                    cursor: pointer;
                    vertical-align: middle;
                    opacity: 0.5;
                    transition: opacity .2s ease-in-out;
                }
                img:hover{
                    opacity: 1; 
                }
                i {
                    font-size: 18px;
                    margin-left: 10px;
                    cursor: pointer;
                    vertical-align: middle;
                }
            }
        }

        .canvs {
            height: calc(100% - 26px);
            width: 100%;
            font-size: 12px;
            position: relative;

            canvas {
                height: 100%;
                width: 100%;
                position: absolute;
                left: 0;
                top: 0;

                &.canvas {
                    z-index: 10;
                }
            }
        }
    }   
</style>